package cn.hzc.fortess.core.aop;

import cn.hzc.fortess.core.common.ResponseData;
import cn.hzc.fortess.core.common.BizErrorEnum;
import cn.hzc.fortess.core.common.exception.InvalidKaptchaException;
import cn.hzc.fortess.core.common.exception.ServiceException;
import cn.hzc.fortess.core.shiro.ShiroKit;
import cn.hzc.fortess.core.common.HttpContext;
import cn.hzc.fortess.core.shiro.ShiroUser;
import cn.hzc.fortess.system.eventbus.BizLogEvent;
import cn.hzc.fortess.system.eventbus.EventExecute;
import cn.hzc.fortess.system.eventbus.LoginLogEvent;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.CredentialsException;
import org.apache.shiro.authc.DisabledAccountException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.http.HttpStatus;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

import java.lang.reflect.UndeclaredThrowableException;


/**
 * Controller全局的的异常拦截器
 */
@ControllerAdvice
@Order(-1)
public class GlobalExceptionHandler {

    private Logger log = LoggerFactory.getLogger(this.getClass());

    /**
     * 拦截业务异常
     */
    @ExceptionHandler(ServiceException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ResponseBody
    public ResponseData bussiness(ServiceException e) {
        EventExecute.me().post(new BizLogEvent(ShiroKit.getUser().getAccount(), HttpContext.getIp(), e));
        HttpContext.getRequest().setAttribute("tip", e.getMessage());
        log.error("业务异常:", e);
        return new ResponseData(false, e.getCode(), e.getMessage(), null);
    }

    @ExceptionHandler(AuthenticationException.class)
    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    public String unAuth(AuthenticationException e, Model model) {
        ShiroUser shiroUser = ShiroKit.getUser();
        EventExecute.me().post(new LoginLogEvent.Builder().ip(HttpContext.getIp())
                .lesseeId(shiroUser != null ? shiroUser.getLesseeId() : 0)
                .logDetail(e.getMessage())
                .loginName(shiroUser != null ? shiroUser.getAccount() : "")
                .logName("登录")
                .logStatus("UNAUTH").uaAgent(HttpContext.getUaAgent()).build());

        model.addAttribute("tips", e.getMessage());

        return "/login.html";
    }

    /**
     * 账号被冻结异常
     */
    @ExceptionHandler(DisabledAccountException.class)
    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    public String accountLocked(DisabledAccountException e, Model model) {
        String username = HttpContext.getRequest().getParameter("username");
        EventExecute.me().post(new LoginLogEvent.Builder().ip(HttpContext.getIp())
                .lesseeId(0)
                .logDetail("账号被冻结")
                .loginName(username)
                .logName("登录")
                .logStatus("FAIL").uaAgent(HttpContext.getUaAgent()).build());


        model.addAttribute("tips", "账号被冻结");
        return "/login.html";
    }

    /**
     * 账号密码错误异常
     */
    @ExceptionHandler(CredentialsException.class)
    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    public String credentials(CredentialsException e, Model model) {
        String username = HttpContext.getRequest().getParameter("username");
        EventExecute.me().post(new LoginLogEvent.Builder().ip(HttpContext.getIp())
                .lesseeId(0)
                .logDetail("账号密码错误")
                .loginName(username)
                .logName("登录")
                .logStatus("FAIL").uaAgent(HttpContext.getUaAgent()).build());
        model.addAttribute("tips", "账号密码错误");
        return "/login.html";
    }

    /**
     * 验证码错误异常
     */
    @ExceptionHandler(InvalidKaptchaException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public String credentials(InvalidKaptchaException e, Model model) {
        String username = HttpContext.getRequest().getParameter("username");
        EventExecute.me().post(new LoginLogEvent.Builder().ip(HttpContext.getIp())
                .lesseeId(0)
                .logDetail("验证码错误")
                .loginName(username)
                .logName("登录")
                .logStatus("FAIL").uaAgent(HttpContext.getUaAgent()).build());
        model.addAttribute("tips", "验证码错误");
        return "/login.html";
    }

    /**
     * 无权访问该资源异常
     */
    @ExceptionHandler(UndeclaredThrowableException.class)
    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    @ResponseBody
    public ResponseData credentials(UndeclaredThrowableException e) {
        EventExecute.me().post(new BizLogEvent(ShiroKit.getUser() != null ? ShiroKit.getUser().getAccount() : "", HttpContext.getIp(), e));
        HttpContext.getRequest().setAttribute("tip", "权限异常");
        log.error("权限异常!", e);
        return new ResponseData(BizErrorEnum.NO_PERMITION);
    }

    /**
     * 拦截未知的运行时异常
     */
    @ExceptionHandler(RuntimeException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ResponseBody
    public ResponseData notFount(RuntimeException e) {
        EventExecute.me().post(new BizLogEvent(ShiroKit.getUser() != null ? ShiroKit.getUser().getAccount() : "", HttpContext.getIp(), e));
        HttpContext.getRequest().setAttribute("tip", "服务器运行时异常:" + e.getMessage());
        log.error("运行时异常:", e);
        if (e instanceof DuplicateKeyException) {
            return new ResponseData(BizErrorEnum.CANT_DATABASE_UNIQUE_KEY);

        }
        return ResponseData.error(BizErrorEnum.SERVER_ERROR.getCode(), e.getMessage());
    }
}
